# -*- coding: utf-8 -*-

from hlm.node import Node
from hlm.lane import *
from hlm.channel import *


def __fetch_port_max_usage(port):
    port_max_usage = {}
    # Ignore several types.
    if isinstance(port, PortOut) or isinstance(port, LanePortSender):
        return None
    # Check port instance type.
    if isinstance(port, PortIn):
        return port.max_history_usage()
    if isinstance(port, LanePortReceiver) or isinstance(port, ChannelPort):
        # For lane or channel port, it needs to iterate all the children.
        for child_name in port.__dict__.keys():
            if child_name.startswith('_'):
                continue
            # Get the lane port maximum usage.
            lane_max_usage = __fetch_port_max_usage(getattr(port, child_name))
            # If lane usage is not None, add to channel port usage.
            if lane_max_usage is not None:
                port_max_usage[child_name] = lane_max_usage
        if len(port_max_usage) == 0:
            return None
        return port_max_usage
    if isinstance(port, list):
        list_usage = []
        for item_port in port:
            port_usage = __fetch_port_max_usage(item_port)
            # Check result.
            if port_usage is not None:
                list_usage.append(port_usage)
        if len(list_usage) > 0:
            return list_usage
        return None
    raise Exception('Unimplemented port type {}.'.format(type(port)))


def __fetch_node_max_usage(node):
    # Check node type.
    if isinstance(node, Node):
        # Fetch node information.
        return statistic_port_max_usage(node)
    if isinstance(node, list):
        # Create list for node.
        return [statistic_port_max_usage(element_node) for element_node in node]
    else:
        raise Exception('Unknown node item type {}'.format(type(node)))


def statistic_port_max_usage(node: Node):
    node_usage = {}
    node_port_usage = {}
    # Check all the ports.
    for port_name in node.port.__dict__.keys():
        # Check the port type, fetch the port information.
        port_usage = __fetch_port_max_usage(getattr(node.port, port_name))
        # Ignore the None ports.
        if port_usage is None:
            continue
        # Add result to node usage
        node_port_usage[port_name] = port_usage
    if len(node_port_usage) > 0:
        node_usage['p'] = node_port_usage
    child_port_usage = {}
    # Loop for all its child node.
    for child_node_name in node.node.__dict__.keys():
        # Fetch the node item.
        child_usage = __fetch_node_max_usage(getattr(node.node, child_node_name))
        # Check node information.
        if child_usage is None:
            continue
        # If child node is list, check its element.
        if isinstance(child_usage, list) and child_usage[0] is None:
            continue
        # Add it to child port usage.
        child_port_usage[child_node_name] = child_usage

    if len(child_port_usage) > 0:
        node_usage['n'] = child_port_usage
    # Check node usage information.
    if len(node_usage) > 0:
        return node_usage
    return None
